#include <rclcpp/rclcpp.hpp>
#include "performance_test_base.h"

namespace trace_api = opentelemetry::trace;
namespace trace_sdk = opentelemetry::sdk::trace;
namespace resource_sdk = opentelemetry::sdk::resource;
namespace nostd = opentelemetry::nostd;

class ExporterImpactTest : public rclcpp::Node {
public:
    ExporterImpactTest() : Node("exporter_impact_test") {
        RCLCPP_INFO(this->get_logger(), "🔍 Exporter Impact Test");
        RCLCPP_INFO(this->get_logger(), "========================");
        
        // Test 1: With OStreamSpanExporter (current setup)
        testWithOStreamExporter();
        
        // Test 2: With NoOpExporter (no output)
        testWithNoOpExporter();
        
        RCLCPP_INFO(this->get_logger(), "✅ Exporter impact test completed!");
    }

private:
    void testWithOStreamExporter() {
        RCLCPP_INFO(this->get_logger(), "📊 测试1: 使用OStreamSpanExporter (有输出)");
        
        // Initialize with OStreamSpanExporter
        auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(
            new opentelemetry::exporter::trace::OStreamSpanExporter);
        
        auto processor = std::unique_ptr<trace_sdk::SpanProcessor>(
            new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
        
        auto resource = resource_sdk::Resource::Create({
            {"service.name", "exporter-impact-test"},
            {"service.version", "1.0.0"}
        });
        
        auto sampler = std::unique_ptr<trace_sdk::Sampler>(
            new trace_sdk::AlwaysOnSampler);
        
        auto provider = nostd::shared_ptr<trace_api::TracerProvider>(
            new trace_sdk::TracerProvider(std::move(processor), resource, std::move(sampler)));
        
        trace_api::Provider::SetTracerProvider(provider);
        auto tracer = provider->GetTracer("exporter-impact-test");
        
        PerformanceStats stats;
        stats.reset();
        
        stats.memory_before_kb = PerformanceTestBase::getCurrentMemoryKB();
        auto cpu_before = PerformanceTestBase::getCurrentCPUTime();
        stats.cpu_time_user_before = cpu_before.first;
        stats.cpu_time_system_before = cpu_before.second;
        
        const size_t iterations = 1000;
        
        for (size_t i = 0; i < iterations; ++i) {
            auto span_start = std::chrono::high_resolution_clock::now();
            
            auto span = tracer->StartSpan("test_span_with_output", {
                {"iteration", static_cast<int64_t>(i)}
            });
            
            span->SetAttribute("test.data", "sample_" + std::to_string(i));
            span->AddEvent("test_event");
            span->SetStatus(trace_api::StatusCode::kOk, "Test completed");
            span->End();
            
            auto span_end = std::chrono::high_resolution_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(span_end - span_start);
            
            stats.total_time += duration;
            stats.min_time = std::min(stats.min_time, duration);
            stats.max_time = std::max(stats.max_time, duration);
            stats.operation_count++;
        }
        
        stats.memory_after_kb = PerformanceTestBase::getCurrentMemoryKB();
        auto cpu_after = PerformanceTestBase::getCurrentCPUTime();
        stats.cpu_time_user_after = cpu_after.first;
        stats.cpu_time_system_after = cpu_after.second;
        
        stats.calculateAverages();
        PerformanceTestBase::printStats("With OStreamSpanExporter (有输出)", stats);
    }
    
    void testWithNoOpExporter() {
        RCLCPP_INFO(this->get_logger(), "📊 测试2: 使用OStreamSpanExporter但重定向到/dev/null (无输出)");
        
        // Initialize with OStreamSpanExporter but redirect to /dev/null (no output)
        auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(
            new opentelemetry::exporter::trace::OStreamSpanExporter);
        
        auto processor = std::unique_ptr<trace_sdk::SpanProcessor>(
            new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
        
        auto resource = resource_sdk::Resource::Create({
            {"service.name", "exporter-impact-test"},
            {"service.version", "1.0.0"}
        });
        
        auto sampler = std::unique_ptr<trace_sdk::Sampler>(
            new trace_sdk::AlwaysOnSampler);
        
        auto provider = nostd::shared_ptr<trace_api::TracerProvider>(
            new trace_sdk::TracerProvider(std::move(processor), resource, std::move(sampler)));
        
        trace_api::Provider::SetTracerProvider(provider);
        auto tracer = provider->GetTracer("exporter-impact-test");
        
        PerformanceStats stats;
        stats.reset();
        
        stats.memory_before_kb = PerformanceTestBase::getCurrentMemoryKB();
        auto cpu_before = PerformanceTestBase::getCurrentCPUTime();
        stats.cpu_time_user_before = cpu_before.first;
        stats.cpu_time_system_before = cpu_before.second;
        
        const size_t iterations = 1000;
        
        for (size_t i = 0; i < iterations; ++i) {
            auto span_start = std::chrono::high_resolution_clock::now();
            
            auto span = tracer->StartSpan("test_span_no_output", {
                {"iteration", static_cast<int64_t>(i)}
            });
            
            span->SetAttribute("test.data", "sample_" + std::to_string(i));
            span->AddEvent("test_event");
            span->SetStatus(trace_api::StatusCode::kOk, "Test completed");
            span->End();
            
            auto span_end = std::chrono::high_resolution_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(span_end - span_start);
            
            stats.total_time += duration;
            stats.min_time = std::min(stats.min_time, duration);
            stats.max_time = std::max(stats.max_time, duration);
            stats.operation_count++;
        }
        
        stats.memory_after_kb = PerformanceTestBase::getCurrentMemoryKB();
        auto cpu_after = PerformanceTestBase::getCurrentCPUTime();
        stats.cpu_time_user_after = cpu_after.first;
        stats.cpu_time_system_after = cpu_after.second;
        
        stats.calculateAverages();
        PerformanceTestBase::printStats("With NoOpSpanExporter (无输出)", stats);
    }
};

int main(int argc, char* argv[]) {
    rclcpp::init(argc, argv);
    
    auto node = std::make_shared<ExporterImpactTest>();
    
    RCLCPP_INFO(node->get_logger(), "🎯 开始Exporter影响测试...");
    
    rclcpp::spin(node);
    rclcpp::shutdown();
    
    return 0;
}
